package org.groovymud.shell.security.loginsteps;

import static org.groovymud.shell.security.loginsteps.CallBackDelegate.createCallbackArray;

import java.io.IOException;
import java.util.Set;

import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.FailedLoginException;

import org.groovymud.shell.security.MudLoginModuleData;
import org.groovymud.shell.security.PlayerCredentials;
import org.groovymud.shell.security.callbacks.SelfHandlingPasswordCallback;

public class RequestPassword extends LoginStep {

    public void execute(MudLoginModuleData data) throws IOException, UnsupportedCallbackException, FailedLoginException {
		if (!data.isGuest()) {
			Callback[] cb;
			PasswordCallback passwordCallback = null;
			PasswordCallback checkPassword = null;

			if (data.getPlayer() == null) {

                checkPassword = new SelfHandlingPasswordCallback("again:", false);
                passwordCallback = new SelfHandlingPasswordCallback("enter a password:", false);

				cb = createCallbackArray(passwordCallback, checkPassword);
			} else {
                passwordCallback = new SelfHandlingPasswordCallback("password: ", false);
				cb = createCallbackArray(passwordCallback);
			}
			data.getCallbackHandler().handle(cb);
			data.setPassword(passwordCallback.getPassword()); // set the password
			boolean passwordValid;
			if (checkPassword != null) {
				passwordValid = checkSamePassword(data.getPassword(), checkPassword.getPassword());
			} else {
				PlayerCredentials testCredentials = new PlayerCredentials(data.getUsername(), String.valueOf(data.getPassword()));
				Subject subject = data.getPlayer().getSubject();
				Set<Object> privateCredentials = subject.getPrivateCredentials();
				passwordValid = privateCredentials.contains(testCredentials);
			}
			if (!passwordValid) {
				throw new FailedLoginException("passwords do not match.");
			}
		}
		if (getNextStep() != null) {
			getNextStep().execute(data);
		}
	}

	protected boolean checkSamePassword(char[] pw, char[] passwordOther) throws FailedLoginException {
		boolean passwordValid = true;
		if (passwordOther.length == 0) {
			throw new FailedLoginException("password cannot be 0 length");
		}
		for (int x = 0; x < passwordOther.length; x++) {
			if (passwordOther[x] != pw[x]) {
				passwordValid = false;
			}
		}
		return passwordValid;
	}
}
